<template>
    <div class="GameBox">
        <div class="top">
            <div class="title">2048</div>
            <div class="scoreBox">
                <div class="current-score">
                    <div class="text">成绩</div>
                    <div class="count">{{ score }}</div>
                </div>
                <div class="best-score">
                    <div class="text">最好成绩</div>
                    <div class="count">{{ bestScore }}</div>
                </div>
            </div>
        </div>

        <div class="game-box">
            <div v-for="(rows,index) in gameArr" :key="index" class="rows">
                <div
                    v-for="(item,ins) in rows"
                    :key="ins"
                    class="item-box"
                    :style="{background: colorText['' + item].bg, color: colorText['' + item].fColor, fontSize: colorText['' + item].fSize}"
                > {{ item}} </div>
            </div>

            <div class="cover" v-if="isOver">
                <p>游戏结束...</p>
                <button @click="onRefresh">再试一次</button>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'GameBox',
    data() {
        return {
            score: 0,
            bestScore: 0,

            gameArr: [
                [0,0,0,0],
                [0,0,0,0],
                [0,0,0,0],
                [0,0,0,0],
            ],
            row: 4,
            col: 4,
            // 记录场上最大的数字
            maxNum: 0,
            // 记录游戏是否结束
            isOver: false,

            colorText: {
                '0': {
                    'bg': '#eee4da59',
                    'fColor': 'transparent',
                    'fSize': '55px',
                },
                '2': {
                    'bg': '#eee4da',
                    'fColor': '#776e65',
                    'fSize': '55px',
                },
                '4': {
                    'bg': '#ede0c8',
                    'fColor': '#776e65',
                    'fSize': '55px',
                },
                '8': {
                    'bg': '#f2b179',
                    'fColor': '#fff',
                    'fSize': '55px',
                },
                '16': {
                    'bg': '#f59563',
                    'fColor': '#fff',
                    'fSize': '55px',
                },
                '32': {
                    'bg': '#f67c5f',
                    'fColor': '#fff',
                    'fSize': '55px',
                },
                '64': {
                    'bg': '#f65e3b',
                    'fColor': '#fff',
                    'fSize': '55px',
                },
                '128': {
                    'bg': '#edcf72',
                    'fColor': '#fff',
                    'fSize': '45px',
                },
                '256': {
                    'bg': '#edc64c',
                    'fColor': '#fff',
                    'fSize': '45px',
                },
                '512': {
                    'bg': '#e3625d',
                    'fColor': '#fff',
                    'fSize': '35px',
                },
                '2048': {
                    'bg': '#e74039',
                    'fColor': '#fff',
                    'fSize': '35px',
                }
            }
        }
    },
    watch: {
    },
    created() {
        let best = localStorage.getItem('bestScore')
        if(best) {
            this.bestScore = best
        }

        this.row = this.gameArr.length
        this.col = this.gameArr&&this.gameArr[0].length

        let that = this
        document.addEventListener("keydown", function(event) {
            let keyCode = event.keyCode
            
            console.log('**疯狂持续按键后再按无反应BUG: 由于事件队列积压**')
            
            // 上
            if(keyCode==38) {
                that.move('top')
            }
            // 下
            else if(keyCode==40){
                that.move('bottom')
            }
            // 左
            else if(keyCode==37){
                that.move('left')
            }
            // 右
            else if(keyCode==39){
                that.move('right')
            }
        })

        // 默认开局随机生成两个2
        this.randomNum2ToGame()
        this.randomNum2ToGame()
    },
    methods: {
        randomNum2ToGame() {
            // 随机生成2
            let i = this.randomNum(this.row)  // [0, row]
            let j = this.randomNum(this.col)  // [0, col]

            while(this.gameArr[i][j]>0) {
                i = this.randomNum(this.row)
                j = this.randomNum(this.col)
            }

            // 当最大数值大于等于256时， 随机生成2或着4
            let value = 2
            if(this.maxNum>=256) {
                value = Math.random() > 0.5 ? 4 : 2
            }

            // this.gameArr[i][j] = value
            this.$set(this.gameArr[i], j, value)
        },
        randomNum(num) {
            return Math.floor(Math.random()*num)  // [0, num]
        },
        move(direction="bottom") {
            // 记录这一部移动合并所得的分数
            let sumScore = 0
            // 中间过渡数组 midleArr
            let midleArr=[], lineArr = []
            for(let i=0; i<this.col; i++) {
                lineArr.push(0)
            }
            for(let j=0; j<this.row; j++) {
                midleArr.push([...lineArr])
            }
            
            // 行i，列j
            let i,j
            if(direction=="top") {
                // 第一列到最后一列
                for(j=0; j<this.col; j++) {
                    let colArr = []
                    for(i=0; i<this.row; i++) {
                        if(this.gameArr[i][j]>0) {
                            colArr.push(this.gameArr[i][j])
                        }
                    }
                    
                    let y=0
                    for(let x=0; x<colArr.length; x++) {
                        if(colArr[x]!=colArr[x+1] && x+1<colArr.length) {
                            midleArr[y][j] = colArr[x]
                            y++
                        }
                        // 合并两个相同的
                        else if(colArr[x]==colArr[x+1] && x+1<colArr.length) {
                            midleArr[y][j] = colArr[x] + colArr[x+1]
                            sumScore = sumScore + midleArr[y][j]
                            x++
                            y++
                        }
                        else if(x==colArr.length-1) {
                            midleArr[y][j] = colArr[x]
                        }
                    }
                }
            }
            else if(direction=="bottom"){
                // 第一列到最后一列
                for(j=0; j<this.col; j++) {
                    let colArr = []
                    for(i=0; i<this.row; i++) {
                        if(this.gameArr[i][j]>0) {
                            colArr.push(this.gameArr[i][j])
                        }
                    }
                    
                    let y=this.row-1
                    for(let x=colArr.length-1; x>=0; x--) {
                        if(colArr[x]!=colArr[x-1] && x-1>=0) {
                            midleArr[y][j] = colArr[x]
                            y--
                        }
                        // 合并两个相同的
                        else if(colArr[x]==colArr[x-1] && x-1>=0) {
                            midleArr[y][j] = colArr[x] + colArr[x-1]
                            sumScore = sumScore + midleArr[y][j]
                            x--
                            y--
                        }
                        else if(x==0) {
                            midleArr[y][j] = colArr[x]
                        }
                    }
                }
            }
            else if(direction=="left"){
                // 第一行到最后一行
                for(i=0; i<this.row; i++) {
                    let rowArr = []
                    for(j=0; j<this.col; j++) {
                        if(this.gameArr[i][j]>0) {
                            rowArr.push(this.gameArr[i][j])
                        }
                    }
                    
                    let y=0
                    for(let x=0; x<rowArr.length; x++) {
                        if(rowArr[x]!=rowArr[x+1] && x+1<rowArr.length) {
                            midleArr[i][y] = rowArr[x]
                            y++

                        }
                        // 合并两个相同的
                        else if(rowArr[x]==rowArr[x+1] && x+1<rowArr.length) {
                            midleArr[i][y] = rowArr[x] + rowArr[x+1]
                            sumScore = sumScore + midleArr[i][y]
                            x++
                            y++                            
                        }
                        else if(x==rowArr.length-1) {
                            midleArr[i][y] = rowArr[x]
                        }
                    }
                }
            }
            else if(direction=="right"){
                // 第一行到最后一行
                for(i=0; i<this.row; i++) {
                    let rowArr = []
                    for(j=0; j<this.col; j++) {
                        if(this.gameArr[i][j]>0) {
                            rowArr.push(this.gameArr[i][j])
                        }
                    }
                    
                    let y=this.col-1
                    for(let x=rowArr.length-1; x>=0; x--) {
                        if(rowArr[x]!=rowArr[x-1] && x-1>=0) {
                            midleArr[i][y] = rowArr[x]
                            y--
                        }
                        // 合并两个相同的
                        else if(rowArr[x]==rowArr[x-1] && x-1>=0) {
                            midleArr[i][y] = rowArr[x] + rowArr[x-1]
                            sumScore = sumScore + midleArr[i][y]
                            x--
                            y--
                        }
                        else if(x==0) {
                            midleArr[i][y] = rowArr[x]
                        }
                    }
                }
            }

            let isChange = 0
            // console.log('midleArr:', midleArr)
            midleArr.forEach((rows, index) => {
                for(let i=0; i<rows.length; i++) {
                    // 找到当前游戏盘中的最大值
                    if(midleArr[index][i]>this.maxNum) {
                        this.maxNum = midleArr[index][i]
                    }
                    // 当检测到执行完这一步的棋盘和之前的棋盘不一样,则表示移动有效
                    if(this.gameArr[index][i]!==midleArr[index][i]) {
                        isChange = 1
                    }
                }

                // 赋值midleArr中间数组的值给数组this.gameArr
                this.$set(this.gameArr, index, [...rows])
            })

            // 每走一步: 1.0 记录这一步得到的的分数和,添加到总分中  2.0 判断最好分数
            this.score = this.score + sumScore
            if(Number(localStorage.getItem('bestScore'))<this.score) {
                localStorage.setItem('bestScore', this.score)
            }

            // 这一步操作有改变this.gameArr数组的值， 则生成一个随机的2 或者 4
            if(isChange==1) {
                let that = this
                setTimeout(()=> {
                    that.randomNum2ToGame()
                }, 200)
            }

            setTimeout(() => {
                this.isOver = this.gameOver()
            })
        },

        // 判断游戏结束
        gameOver() {
            // 遍历每一个元素， 他的上/下/左/右都不为0且和元素的值不相等，则表示数组全部都填满且四个方向上移动也不能发生合并项了
            for(let i=0; i<this.row; i++) {
                for(let j=0; j<this.col; j++) {
                    let currentValue = this.gameArr[i][j]
                    // 存在为0的元素，游戏继续
                    if(currentValue==0){
                        return false
                    }
                    else {
                        // if((i-1)>=0 && currentValue==this.gameArr[i-1][j]){
                        //     return false
                        // }
                        if((i+1)<this.row && currentValue==this.gameArr[i+1][j]){
                            return false
                        }
                        // if((j-1)>=0 && currentValue==this.gameArr[i][j-1]){
                        //     return false
                        // }
                        if((j+1)<this.col && currentValue==this.gameArr[i][j+1]){
                            return false
                        }
                    }
                }
            }
            return true
        },
        onRefresh() {
            location.reload()
        }
    }
}
</script>

<style scoped lang="scss">
.GameBox {
    width: 500px;
    margin: 30px auto;

    display: flex;
    flex-wrap: wrap;
    justify-content: center;

    .top {
        width: 100%;
        display: flex;
        align-content: center;
        justify-content: space-between;

        padding: 10px;
        box-sizing: border-box;
        font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif;
        margin-bottom: 40px;

        .title {
            font-size: 80px;
            font-weight: bold;
        }
        .scoreBox {
            display: flex;
            align-items: center;

            .current-score, .best-score {
                display: inline-block;
                background-color: #bbada0;
                border-radius: 5px;
                padding: 10px 15px;
                min-width: 80px;
                margin: 0 5px;
                text-align: center;

                .text {
                    color: #eee4da;
                }

                .count {
                    margin-top: 5px;
                    font-size: 25px;
                    font-weight: bold;
                    color: #fff;
                }
            }
        }
    }

    .game-box {
        display: inline-block;
        background-color: #bbada0;
        padding: 8px;
        border-radius: 6px;
        font-size: 0;
        position: relative;

        .rows {
            display: flex;
            .item-box {
                width: 100px;
                height: 100px;
                // border: 8px solid #bbada0;
                border-radius: 3px;
                margin: 8px;
                overflow: hidden;
                background-color: #eee4da59;
                font-size: 55px;
                color: #776e65;
                font-weight: bold;

                display: inline-block;
                padding: 0;

                display: flex;
                align-items: center;
                justify-content: center;
            }
        }
        
        .cover {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            background-color: rgba($color: #fff, $alpha: 0.4);

            display: flex;
            align-content: center;
            justify-content: center;
            flex-wrap: wrap;

            p {
                width: 100%;
                text-align: center;
                color: #fff;
                font-size: 24px;
                font-weight: bold;
            }

            button {
                padding: 10px 20px;
                border: unset;
                background-color: #ff9800;
                color: #fff;
                border-radius: 6px;
                font-size: 17px;
                font-weight: bold;
            }
        }
    }
}
</style>
